﻿// ***********************************************************************
// Assembly         : GooglePredict
// Author           : aj
// Created          : 10-08-2010
//
// Last Modified By : aj
// Last Modified On : 10-08-2010
// Description      : 
//
//
// ***********************************************************************
namespace Google.API.Predict.Requests
{
    using System;
    using System.Linq;
    using Core;
    using Features;
    using Newtonsoft.Json;
    using Newtonsoft.Json.Linq;
    using Responses;

    /// <summary>
    /// Prediction Request Class
    /// http://code.google.com/apis/predict/docs/developer-guide.html#predict
    /// </summary>
    /// <typeparam name="TPredictionType">Prediction query type (Text, Numeric, Mixed) - See Google.API.Predict.Requests</typeparam>
    public class PredictionRequest<TPredictionType> : GooglePredictionApiRequest<PredictionResponse> where TPredictionType : IFeature
    {
        /// <summary>
        /// Hide this - useless without prediction query features
        /// </summary>
        private PredictionRequest() { }

        /// <summary>
        /// Creates a new Prediction Request (Querying)
        /// </summary>
        /// <param name="p">Prediction query - features to be POSTed</param>
        public PredictionRequest(TPredictionType p)
        {
            RequestFormat = "{0}/{1}%2F{2}/predict";
            PredictionFeatures = p;
            Method = HttpMethod.Post;
        }

        /// <summary>
        /// Prediction features that get POSTed
        /// </summary>
        public TPredictionType PredictionFeatures { get; set; }

        /// <summary>
        /// Executes the Prediction request
        /// Parses response and stores in "Response" field
        /// Fully supports "outputMulti" for categorical outputs
        /// </summary>
        /// <returns>Parsed JSON response</returns>
        internal override JObject Execute()
        {
            // SET POST DATA
            // WE ARE SETTING IT HERE TO ACCOUNT FOR ANY CHANGES BETWEEN INSTANTIATION AND EXECUTION
            try
            {
                var dataString = JsonConvert.SerializeObject(PredictionFeatures);
                PostData = new System.Collections.ObjectModel.ReadOnlyCollection<byte>(System.Text.Encoding.ASCII.GetBytes(dataString));
            }
            catch (Exception e)
            {
                Response.InnerException = e;
                Response.Success = false;
                Response.OutputType = PredictionResponse.PredictionOutputType.Unknown;
                return null;
            }

            // EXECUTE THE REQUEST
            var o = base.Execute();

            // DETERMINE OUTPUT TYPE
            if (Response.Success)
            {
                Response.OutputType = !string.IsNullOrEmpty(Response.OutputLabel) ? PredictionResponse.PredictionOutputType.Categorical : PredictionResponse.PredictionOutputType.Regression;
                    
                // MULTI OUTPUT PARSING
                var multi = o["data"]["outputMulti"];
                if (multi != null)
                {
                    try
                    {
                        Response.OutputMulti =
                            new System.Collections.ObjectModel.Collection<MultiOutput>(
                                multi.Children().Select(j => JsonConvert.DeserializeObject<MultiOutput>(j.ToString())).
                                    OrderByDescending(m => m.Score).ToArray());
                    }
                    catch (Exception e)
                    {
                        Response.InnerException = e;
                        Response.Success = false;
                    }
                }
            }
            else
            {
                Response.OutputType = PredictionResponse.PredictionOutputType.Unknown;
            }

            return o;
        }
    }
}
